package ca.csf.dfc.poo.engine;

import java.util.Random;

import ca.csf.dfc.poo.environnement.Case;
import ca.csf.dfc.poo.environnement.Environnement;
import ca.csf.dfc.poo.environnement.Interdit;
import ca.csf.dfc.poo.environnement.Plancher;
import ca.csf.dfc.poo.environnement.Prise;
import ca.csf.dfc.poo.environnement.Robot;
import ca.csf.dfc.poo.environnement.RobotAleatoire;
import ca.csf.dfc.poo.environnement.RobotIntelligent;
import ca.csf.dfc.poo.environnement.RobotLineaire;
import ca.csf.dfc.poo.environnement.RobotVorace;
import ca.csf.dfc.poo.environnement.Tapis;
import ca.csf.dfc.poo.exceptions.IllegalPositionXException;
import ca.csf.dfc.poo.exceptions.IllegalPositionYException;
import ca.csf.dfc.poo.exceptions.IllegalRecompenseException;
import ca.csf.dfc.poo.exceptions.IllegalTableauDecisionException;
import ca.csf.dfc.poo.exceptions.InvalidDirectionException;

public class Engine
{
    /**
     * Tableau contenant les robots de la simulation.
     */
	private Robot[] m_MesRobot;
	
	/**
	 * Environnement permettant aux robots de se déplacer.
	 */
	private Environnement monEnvironnement;
	
	/**
	 * Constructeur par initialisation de l'engine.
	 * @param p_Robot un tableau contenant le type des robots.
	 * @param p_maGrille Le nom du fichier contenant l'environnement.
	 * @throws IllegalPositionXException
	 * @throws IllegalPositionYException
	 * @throws IllegalRecompenseException
	 * @throws InvalidDirectionException
	 */
	public Engine(int[] p_Robot,String p_maGrille) throws IllegalPositionXException, IllegalPositionYException, IllegalRecompenseException, InvalidDirectionException
	{
		m_MesRobot=new Robot[p_Robot.length];
		
		monEnvironnement = new Environnement(p_maGrille);
		int largeur = this.monEnvironnement.GetLargeur();
		int hauteur = this.monEnvironnement.GetHauteur();
		
		for(int i = 0; i<p_Robot.length; i++)
		{
			
			int[] position = this.xyRamdom(largeur,hauteur);
			
			switch(p_Robot[i])
			{
			case 1:
				RobotAleatoire monAleatoire = new RobotAleatoire(position[0],position[1]);
				this.setMesRobot(i, monAleatoire);
				break;
			case 2:
				RobotVorace monVorace = new RobotVorace(position[0],position[1]);
				this.setMesRobot(i, monVorace);
				break;
			case 3:
				RobotIntelligent monIntelligent = new RobotIntelligent(position[0],position[1],largeur,hauteur);
				this.setMesRobot(i, monIntelligent);
				break;
			case 4:
				RobotLineaire monLineaire = new RobotLineaire(position[0],position[1]);
				this.setMesRobot(i, monLineaire);
				break;
			}
		}
	}
	
	/**
	 * Retourne la liste de mesRobot.
	 * @return the mesRobot
	 */
	public Robot[] getMesRobot()
	{
		return this.m_MesRobot;
	}

	/**
	 * Pour modifier mes mesRobot.
	 * @param p_Position Position dans le tableau de Robots.
	 * @param p_mesRobot Robot à mettre dans le tableau.
	 */
	public void setMesRobot(int p_Position, Robot p_Robot)
	{
		this.m_MesRobot[p_Position] = p_Robot;
	}
	

	/**
	 * Retourne le monEnvironnement.
	 * @return the monEnvironnement
	 */
	public Environnement getMonEnvironnement()
	{
		return this.monEnvironnement;
	}

	/**
	 * Permet de déplacer les robots.
	 * @param p_nbTours Nombre de tours de déplacement.
	 * @throws IllegalPositionXException
	 * @throws IllegalPositionYException
	 * @throws IllegalTableauDecisionException
	 * @throws InvalidDirectionException
	 * @throws IllegalRecompenseException
	 */
	public void deplacerRobot(int p_nbTours) throws IllegalPositionXException, IllegalPositionYException, IllegalTableauDecisionException, InvalidDirectionException, IllegalRecompenseException
	{
		for(int i = 0; i<p_nbTours; i++)
		{
			for(Robot r:this.getMesRobot())
			{
				Case[] montab = this.monEnvironnement.GetVoisin(r.getX(),r.getY());
				
				//On vérifie si une case est interdite, on la met à null pour l'envoyer au robot
				for(int j = 0; j< montab.length ; j++)
				{
					if(montab[j] instanceof Interdit)
					{
						montab[j] = null;
					}
				}

				int decision =r.prendreDecision(montab);
				if(decision != -1)
				{
    				executerDeplacement(decision, r);
    				r.recevoirRecompense(montab[decision].getRecompense());
    				
    				//Si le robot va sur une prise, on le fait réapparaitre à un endroit au hasard
    				if(montab[decision] instanceof Prise)
    				{
    					int largeur = this.monEnvironnement.GetLargeur();
    					int hauteur = this.monEnvironnement.GetHauteur();
    					int[] position = this.xyRamdom(largeur,hauteur);
    					r.deplacer(position[0], position[1]);					
    				}
				}
			}
		}
	}
	
	/**
	 * Exécute le déplacement d'un robot.
	 * @param p_Direction La direction dans laquelle déplacer le robot.
	 * @param p_Robot Le robot à déplacer.
	 * @throws IllegalPositionXException
	 * @throws IllegalPositionYException
	 */
	private void executerDeplacement(int p_Direction, Robot p_Robot) throws IllegalPositionXException, IllegalPositionYException
	{
		switch (p_Direction)
		{
			case 0:
				p_Robot.deplacer(p_Robot.getX(), p_Robot.getY()-1);
				break;
			case 1:
				p_Robot.deplacer(p_Robot.getX()+1,p_Robot.getY());
				break;
			case 2:
				p_Robot.deplacer(p_Robot.getX(), p_Robot.getY()+1);
				break;
			case 3:
				p_Robot.deplacer(p_Robot.getX()-1, p_Robot.getY());
				break;
		}
	}
	
	/**
	 * Choisi une position x et y situé entre dans l'environnement.
	 * @param p_Largeur Largeur de l'environnement.
	 * @param p_Hauteur Hauteur de l'environnement.
	 * @return un tableau de 2 int (position x,y).
	 */
	private int[] xyRamdom(int p_Largeur, int p_Hauteur)
	{
		int[] position= new int[2];
		
		do
		{
			Random largeur = new Random();
			Random hauteur = new Random();
			position[0] = largeur.nextInt(p_Largeur);
			position[1] = hauteur.nextInt(p_Hauteur);
			
		}while(!this.getMonEnvironnement().CaseValide(position[0],position[1]));
		
		return position;
	}
}
	
	

